from common.object import (
    CTickData,
    CBarData,
    TradeData,
    OrderData,
    CArbBarData,
)
from strategies.base import StopOrder, SpreadOrder
from strategies.template import CtaTemplate
import pandas as pd
import numpy as np
import datetime as dt
import math
import copy
from Engine.engine import BacktestingEngine
import operator
import types


class CombineStrategy(CtaTemplate):
    """"""

    author = "Jie"

    parameters = []
    variables = []

    def __init__(self, cta_engine, strategy_name, vt_symbols, setting):
        """"""
        super(CombineStrategy, self).__init__(
            cta_engine, strategy_name, vt_symbols, setting
        )
        self.__strategy_num = 0
        self.strategy_list = []

    def add_strategy(self, strategy_class, strategy_name, vt_symbols, setting):
        strategy = strategy_class(self.cta_engine, strategy_name, vt_symbols, setting)
        strategy.set_sub_strategy_id(self.__strategy_num)
        strategy.get_strategy_group_num = self.get_strategy_num
        strategy.get_sibling_strategy = self.get_children_sibling
        self.strategy_list.append(strategy)
        self.__strategy_num += 1

    def get_strategy_num(self):
        return self.__strategy_num

    def get_strategy_group_num(self):
        return self.get_strategy_num()

    def get_children_sibling(self, sid):
        return self.strategy_list[sid]

    def set_inited(self, flag):
        super().set_inited(flag)
        for strategy in self.strategy_list:
            strategy.set_inited(flag)

    def set_trading(self, flag):
        super().set_trading(flag)
        for strategy in self.strategy_list:
            strategy.set_trading(flag)

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        method = operator.methodcaller("on_init")
        list(map(method, self.strategy_list))

    def on_start(self):
        """
        Callback when strategy is started.
        """
        method = operator.methodcaller("on_start")
        list(map(method, self.strategy_list))

    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        method = operator.methodcaller("on_stop")
        list(map(method, self.strategy_list))

    def on_tick(self, tick: CTickData):
        """
        Callback of new tick data update.
        """
        method = operator.methodcaller("on_tick", tick)
        list(map(method, self.strategy_list))

    def on_bar(self, bar: CBarData):
        """
        Callback of new bar data update.
        """
        method = operator.methodcaller("on_bar", bar)
        list(map(method, self.strategy_list))

    def on_arb_bar(self, arbBar: CArbBarData):
        """
        Callback of new bar data update.
        """
        method = operator.methodcaller("on_arb_bar", arbBar)
        list(map(method, self.strategy_list))

    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        self.strategy_list[order.sub_strategy_id].on_order(order)

    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        self.strategy_list[trade.sub_strategy_id].on_trade(trade)
        method = operator.methodcaller("on_group_trade", trade)
        list(map(method, self.strategy_list))

    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        self.strategy_list[stop_order.sub_strategy_id].on_stop_order(stop_order)

    def on_spread_order(self, spread_order: SpreadOrder):
        """
        Callback of spread order update.
        """
        self.strategy_list[spread_order.sub_strategy_id].on_spread_order(spread_order)

    def on_new_day(self, trading_day: int):
        """
        Callback of a new trading day.
        """
        method = operator.methodcaller("on_new_day", trading_day)
        list(map(method, self.strategy_list))

    def on_iteration_end(self, trading_day: int):
        method = operator.methodcaller("on_iteration_end", trading_day)
        list(map(method, self.strategy_list))